package cn.acheng1314.springboot2.model

import cn.acheng1314.exceptions.ForbiddenException
import cn.acheng1314.exceptions.NotFoundException
import cn.acheng1314.exceptions.UnauthorizedException
import com.fasterxml.jackson.annotation.JsonInclude
import org.springframework.http.HttpStatus
import java.io.Serializable
import javax.validation.ConstraintViolationException

/**
 * 返回数据实体包装
 * @author cheng
 */
class ResponseWrap<T> : Serializable {
    var code: Int = 200
    var msg: String = "OK"
    @JsonInclude(JsonInclude.Include.NON_NULL)
    var data: Any? = null
    @JsonInclude(JsonInclude.Include.NON_NULL)
    var pageNum: Int? = null
    @JsonInclude(JsonInclude.Include.NON_NULL)
    var pageSize: Int? = null

    @JvmOverloads
    fun warp(data: T?, msg: String? = null): ResponseWrap<T> {
        when (data) {
            null -> return notFound()
            is HttpStatus -> return initHttpCode(data)
            is Collection<*> -> return list(data, msg)
            is Exception -> return exception(data)
        }
        return ok(data, msg)
    }

    fun page(pageNum: Int, pageSize: Int): ResponseWrap<T> {
        this.pageNum = pageNum
        this.pageSize = pageSize
        return this
    }

    private fun ok(data: Any?, msg: String?): ResponseWrap<T> {
        this.code = HttpStatus.OK.value()
        this.msg = msg ?: HttpStatus.OK.reasonPhrase
        this.data = data
        return this
    }

    private fun list(data: Collection<*>, msg: String?) = if (data.isEmpty()) empty() else ok(data, msg)

    /**
     * 异常处理包装
     */
    private fun exception(data: Any?): ResponseWrap<T> {
        this.code = HttpStatus.INTERNAL_SERVER_ERROR.value()
        val cause: Throwable = data as Throwable
        this.msg = cause.message ?: HttpStatus.INTERNAL_SERVER_ERROR.reasonPhrase
        when (cause) {
            is NotFoundException -> return notFound(cause.message)
            is ConstraintViolationException -> {
                this.code = HttpStatus.INTERNAL_SERVER_ERROR.value()
            }
            is UnauthorizedException -> code = HttpStatus.UNAUTHORIZED.value()
            is ForbiddenException -> code = HttpStatus.FORBIDDEN.value()
        }
        return this
    }

    private fun empty(): ResponseWrap<T> {
        this.code = HttpStatus.NO_CONTENT.value()
        this.msg = HttpStatus.NO_CONTENT.reasonPhrase
        return this
    }

    @JvmOverloads
    private fun notFound(msg: String? = null): ResponseWrap<T> {
        this.code = HttpStatus.NOT_FOUND.value()
        this.msg = msg ?: HttpStatus.NOT_FOUND.reasonPhrase
        return this
    }

    private fun initHttpCode(httpCode: HttpStatus): ResponseWrap<T> {
        this.code = httpCode.value()
        this.msg = httpCode.reasonPhrase
        return this
    }

}